package com.googlecode.allinclusive.fw.database.hibernate.impl;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.googlecode.allinclusive.fw.core.pagination.Pagination;
import com.googlecode.allinclusive.fw.database.hibernate.EntityManager;

/*
 * <bean id="sessionFactory" class="org.springframework.orm.hibernate3.AnnotationSessionFactoryBean">
 * 		<property name="dataSource" ref="****"/>
 * 		<property name="hibernateProperties" >
 * 			<props>
 * 				<prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
 * 				<prop key="hibernate.show_sql">true</prop>
 * 			</props>
 * 		</property>
 * </bean> 
 * 
 * <bean id="entityManager" class="com.googlecode.allinclusive.fw.database.hibernate.impl.EntityManagerHibernateImpl">
 * 		<property name="sessionFactory" ref="sessionFactory"/>
 * </bean>
 */
@SuppressWarnings({"unchecked", "rawtypes"})
public class EntityManagerHibernateImpl extends HibernateDaoSupport implements EntityManager {

	/**
	 * 根据ID获取数据对象
	 * @param clazz 数据对象类型
	 * @param id 标识ID(PK)
	 * 
	 * @return 数据对象
	 */
    public <T> T get(final Class<T> clazz, final Serializable id) {
    	return getHibernateTemplate().get(clazz, id);
    }

    /**
     * 保存数据对象
     * @param entity 数据对象
     * 
     * @return 标识ID(PK)
     */
	public Serializable save(final Object entity) throws DataAccessException {
		return getHibernateTemplate().save(entity);
	}
	
    /**
     * 保存数据对象
     * @param collection 数据对象
     * 
     * @return 标识ID(PK)
     */
	public Collection<Serializable> save(Collection collection) {
		Collection<Serializable> serializables = new ArrayList<Serializable>();
		if (collection == null || collection.isEmpty()) {
			return serializables;
		}
		// loop
		for (Object entity : collection) {
			serializables.add(save(entity));
		}
		
		return serializables;
	}

    /**
     * 更新数据对象
     * @param entity 数据对象
     */
	public void update(Object entity) throws DataAccessException {
		getHibernateTemplate().update(entity);
	}
	
    /**
     * 更新数据对象
     * @param collection 数据对象
     */
	public void update(Collection collection) {
		if (collection == null || collection.isEmpty()) {
			return;
		}
		// loop
		for (Object entity : collection) {
			update(entity);	
		}
	}

    /**
     * 更新数据对象
     * @param entity 数据对象
     */
	public void saveOrUpdate(final Object entity) throws DataAccessException {
		getHibernateTemplate().saveOrUpdate(entity);
	}

    /**
     * 更新数据对象
     * @param collection 数据对象
     */
	public void saveOrUpdate(Collection collection) {
		if (collection == null || collection.isEmpty()) {
			return;
		}
		// loop
		for (Object entity : collection) {
			saveOrUpdate(entity);	
		}
	}
	
    /**
     * 删除数据对象
     * @param entity 数据对象
     */
	public void delete(Object entity) throws DataAccessException {
		getHibernateTemplate().delete(entity);
	}
	
    /**
     * 删除数据对象
     * @param collection 数据对象
     */
	public void delete(Collection collection) {
		if (collection == null || collection.isEmpty()) {
			return;
		}
		// loop
		for (Object entity : collection) {
			delete(entity);	
		}
	}
	
	/**
	 * 查询数据
	 */
	public <T> T queryObject(DetachedCriteria criteria) {
		List<T> objects = queryObjectList(criteria);
		if (objects != null && !objects.isEmpty()) {
			return objects.get(0);
		}
		return null;
	}
	
	/**
	 * 查询数据
	 */
	public <T> List<T> queryObjectList(DetachedCriteria criteria) {
		return getHibernateTemplate().findByCriteria(criteria);
	}
	
	/**
	 * 查询数据
	 */
	public <T> List<T> queryObjectList(DetachedCriteria criteria, int firstResult, int maxResults) {
		return getHibernateTemplate().findByCriteria(criteria, firstResult, maxResults);
	}
	
	/**
	 * 查询指定页的记录
	 * 
	 * @param criteria 条件
	 * @param pagination 分页信息
	 * 
	 * @return 指定页的记录
	 */
	public <T> List<T> queryObjectList(final DetachedCriteria criteria, final Pagination pagination) throws DataAccessException {
		// 分页处理
		if (pagination != null) {
			// 总记录数
			getHibernateTemplate().executeWithNativeSession(new HibernateCallback<T>() {
				@Override
				public T doInHibernate(Session session) throws HibernateException {
					
					Criteria executableCriteria = criteria.getExecutableCriteria(session);
					Number totalCount = (Number) executableCriteria.setProjection(Projections.rowCount()).uniqueResult();
					if (totalCount != null) {
						pagination.setTotalCount(totalCount.intValue());
					}
					return null;
				}
			});
		}
		// 排序
		if (pagination.getOrders() != null) {
			for (Order order : pagination.getOrders()) {
				criteria.addOrder(order);
			}
		}
		
		return queryObjectList(criteria, pagination.getStartIndex(), pagination.getPageSize());
	}
	
	/**
	 * 根据HQL语句查询记录
	 * @param sql HQL语句
	 * @param params 参数
	 * @return 查询结果
	 */
	public <T> T queryObjectByHQL(String sql, final Object[] params) {
		List<T> objects = queryObjectListByHQL(sql, params);
		if (objects != null && !objects.isEmpty()) {
			return objects.get(0);
		}
		return null;
	}
	
	/**
	 * 根据HQL语句查询记录
	 * @param sql HQL语句
	 * @param params 参数
	 * @return 查询结果
	 */
	public <T> List<T> queryObjectListByHQL(String sql, final Object[] params) {
		return getHibernateTemplate().find(sql, params);
	}
	
	/**
	 * 执行HQL语句
	 * @param sql HQL语句
	 * @param params 参数
	 * @return 执行结果
	 */
	public int executeHQL(String sql, final Object[] params) {
		return getHibernateTemplate().bulkUpdate(sql, params);
	}
	
	/**
	 * 计算符合条件的记录总数
	 * @param criteria 查询条件
	 * @return 记录总数
	 */
	public int rowCount(final DetachedCriteria criteria) {
		// 总记录数
		return getHibernateTemplate().executeWithNativeSession(new HibernateCallback<Integer>() {
			@Override
			public Integer doInHibernate(Session session) throws HibernateException {
				Criteria executableCriteria = criteria.getExecutableCriteria(session);
				Number totalCount = (Number) executableCriteria.setProjection(Projections.rowCount()).uniqueResult();
				return totalCount.intValue();
			}
		});
	}	
}
